package com.java.base.io;

/**
 * https://blog.csdn.net/yjp198713/article/details/79270007
 * <p>
 * https://blog.csdn.net/yjp198713/article/details/79281237
 * <p>
 * https://blog.csdn.net/yjp198713/article/details/79298020
 * <p>
 * https://blog.csdn.net/yjp198713/article/details/79300420
 * <p>
 * https://blog.csdn.net/yjp198713/article/details/79309260
 * <p>
 * https://blog.csdn.net/yjp198713/article/details/79320011
 * <p>
 * https://blog.csdn.net/yjp198713/article/details/79362844
 * <p>
 * https://blog.csdn.net/yjp198713/article/details/79363822
 *
 * @author xuweizhi
 * @date 2019/03/19 15:06
 */
public class IoMultiplexing {

    /**
     * <h2>多路复用IO模型</h2>
     * <h3>场景描述</h3>
     * <p>
     * 一个餐厅同时有100位客人到店，当然到店后第一件要做的事情就是点菜。但是问题来了，餐厅老板
     * 为了节约人力成本目前只有一位大堂服务员拿着唯一的一本菜单等待客人进行服务。
     * <p>
     * <b>方法A</b>：无论有多少客人等待点餐，服务员都把仅有的一份菜单递给其中一位客人，然后站在客人身
     * 旁等待这个客人完成点菜过程。在记录客人点菜内容后，把点菜记录交给后堂厨师。然后是第二位客
     * 人。。。。然后是第三位客人。很明显，只有脑袋被门夹过的老板，才会这样设置服务流程。因为随
     * 后的80位客人，再等待超时后就会离店（还会给差评）。
     * <p>
     * <b>方法B</b>：老板马上新雇佣99名服务员，同时印制99本新的菜单。每一名服务员手持一本菜单负责一位
     * 客人（关键不只在于服务员，还在于菜单。因为没有菜单客人也无法点菜）。在客人点完菜后，记录
     * 点菜内容交给后堂厨师（当然为了更高效，后堂厨师最好也有100名）。这样每一位客人享受的就是
     * VIP服务咯，当然客人不会走，但是人力成本可是一个大头哦（亏死你）。
     * <p>
     * <b>方法C</b>：就是改进点菜的方式，当客人到店后，自己申请一本菜单。想好自己要点的才后，就呼叫服务
     * 员。服务员站在自己身边后记录客人的菜单内容。将菜单递给厨师的过程也要进行改进，并不是每一
     * 份菜单记录好以后，都要交给后堂厨师。服务员可以记录号多份菜单后，同时交给厨师就行了。那么
     * 这种方式，对于老板来说人力成本是最低的；对于客人来说，虽然不再享受VIP服务并且要进行一定
     * 的等待，但是这些都是可接受的；对于服务员来说，基本上她的时间都没有浪费，基本上被老板压杆
     * 了最后一滴油水。
     * <p>
     * <b>到店情况</b>：并发量。到店情况不理想时，一个服务员一本菜单，当然是足够了。所以不同的老板在不
     * 同的场合下，将会灵活选择服务员和菜单的配置。
     * <p>
     * <b>客人</b> ：客户端请求
     * <p>
     * <b>点餐内容</b>：客户端发送的实际数据
     * <p>
     * <b>老板</b>：操作系统
     * <p>
     * <b>人力成本</b>：系统资源
     * <p>
     * <b>菜单</b>：文件状态描述符。操作系统对于一个进程能够同时持有的文件状态描述符的个数是有限制的，
     * 在linux系统中$ulimit -n查看这个限制值，当然也是可以（并且应该）进行内核参数调整的。
     * <p>
     * <b>服务员</b>：操作系统内核用于IO操作的线程（内核线程）
     * <p>
     * <b>厨师</b>：应用程序线程（当然厨房就是应用程序进程咯）
     * <p>
     * <b>餐单传递方式</b>：包括了阻塞式和非阻塞式两种。
     * <ul>
     * <li>方法A：阻塞式/非阻塞式 同步IO</li>
     * <li>方法B：使用线程进行处理的 阻塞式/非阻塞式 同步IO</li>
     * <li>方法C：阻塞式/非阻塞式 多路复用IO</li>
     * </ul>
     *
     * <h2>多路复用IO实现方式</h2>
     *
     * 目前流程的多路复用IO实现主要包括四种：select、poll、epoll、kqueue。下表是他们的一些重要特性的比较：
     *
     * IO模型	相对性能	关键思路	            操作系统	        JAVA支持情况
     * select	较高	    Reactor	            windows/Linux	支持,Reactor模式(反应器设计模式)。Linux操作系统的 kernels 2.4内核版本之前，默认使用select；而目前windows下对同步IO的支持，都是select模型
     * poll	    较高	    Reactor	            Linux	        Linux下的JAVA NIO框架，Linux kernels 2.6内核版本之前使用poll进行支持。也是使用的Reactor模式
     * epoll	高	    Reactor/Proactor	Linux	        Linux kernels 2.6内核版本及以后使用epoll进行支持；Linux kernels 2.6内核版本之前使用poll进行支持；另外一定注意，由于Linux下没有Windows下的IOCP技术提供真正的 异步IO 支持，所以Linux下使用epoll模拟异步IO
     * kqueue	高	    Proactor	        Linux	        目前JAVA的版本不支持
     *
     * 多路复用IO技术最适用的是“高并发”场景，所谓高并发是指1毫秒内至少同时有上千个连接
     * 请求准备好。其他情况下多路复用IO技术发挥不出来它的优势。另一方面，使用JAVA NIO
     * 进行功能实现，相对于传统的Socket套接字实现要复杂一些，所以实际应用中，需要根据
     * 自己的业务需求进行技术选择。
     */
    public static void main(String[] args) {


    }
}
